package edu.xidian.cnmano.Informerjob;

import edu.xidian.cnmano.service.DeploymentInfoService;
import edu.xidian.cnmano.service.NodeInfoService;
import edu.xidian.cnmano.service.PodInfoService;
import edu.xidian.cnmano.service.ServiceInfoService;
import edu.xidian.cnmano.util.K8sElementInfoUtil;
import io.kubernetes.client.informer.ResourceEventHandler;
import io.kubernetes.client.informer.SharedIndexInformer;
import io.kubernetes.client.informer.SharedInformerFactory;
import io.kubernetes.client.openapi.models.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

/**
 * @author zhr 为Informer增加回调函数，分别在增改删事件下进行数据库增删改的处理
 * @date 2020/11/28-9:27
 */
@Component
@Slf4j
public class InformerJobs {

    @Resource
    SharedIndexInformer<V1Pod> V1PodInformer;

    @Resource
    SharedIndexInformer<V1Node> V1NodeInformer;

    @Resource
    SharedIndexInformer<V1Deployment> V1DeploymentInformer;

    @Resource
    SharedIndexInformer<V1Service> v1ServiceInformer;

    @Resource
    private PodInfoService podInfoService;

    @Resource
    private DeploymentInfoService deploymentInfoService;

    @Resource
    private NodeInfoService nodeInfoService;

    @Resource
    private ServiceInfoService serviceInfoService;

    @Resource
    private SharedInformerFactory sharedInformerFactory;

    private Long startTime;

    private Long endTime;

    @PostConstruct
    public void runAllInformers() {
        addV1PodInformerEventHandler();
        addV1NodeInformerEventHandler();
        addV1DeploymentInformerEventHandler();
        addV1ServiceInformerEventHandler();
        sharedInformerFactory.startAllRegisteredInformers();
    }

    private void addV1ServiceInformerEventHandler() {
        v1ServiceInformer.addEventHandler(new ResourceEventHandler<V1Service>() {
            @Override
            public void onAdd(V1Service service) {
                String serviceName = service.getMetadata().getName();
                String namespace = service.getMetadata().getNamespace();
                //log.info("{} service added!\n", serviceName);
                try {
                    if (serviceInfoService.getServiceInfoByServiceNameAndNamespace(serviceName, namespace) != null) {
                        serviceInfoService.updateServiceInfo(K8sElementInfoUtil.V1ServiceToServiceInfo(service));
                    } else {
                        serviceInfoService.insertServiceInfo(K8sElementInfoUtil.V1ServiceToServiceInfo(service));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onUpdate(V1Service oldService, V1Service newService) {
                //log.info("{} => {} service updated!\n",oldService.getMetadata().getName(), newService.getMetadata().getName());
                if (oldService.getMetadata().getName().equals(newService.getMetadata().getName())) {
                    serviceInfoService.updateServiceInfo(K8sElementInfoUtil.V1ServiceToServiceInfo(newService));
                } else {
                    onDelete(oldService, false);
                    onAdd(newService);
                }
            }

            @Override
            public void onDelete(V1Service service, boolean deletedFinalStateUnknown) {
                String serviceName = service.getMetadata().getName();
                //log.info("{} service deleted!\n", serviceName);
                serviceInfoService.deleteServiceInfo(K8sElementInfoUtil.V1ServiceToServiceInfo(service));
            }
        });
    }

    private void addV1PodInformerEventHandler() {
        V1PodInformer.addEventHandler(new ResourceEventHandler<V1Pod>() {
            @Override
            public void onAdd(V1Pod pod) {
                String podName = pod.getMetadata().getName();
                String namespace = pod.getMetadata().getNamespace();
                //log.info("{} pod added!\n", podName);
                try {
                    if (podInfoService.getPodInfoByPodNameAndNamespace(podName, namespace) != null) {
                        podInfoService.updatePodInfo(K8sElementInfoUtil.V1PodToPodInfo(pod));
                    } else {
                        podInfoService.insertPodInfo(K8sElementInfoUtil.V1PodToPodInfo(pod));
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onUpdate(V1Pod oldPod, V1Pod newPod) {
                //log.info("{} => {} pod updated!\n",oldPod.getMetadata().getName(), newPod.getMetadata().getName());
                if (oldPod.getMetadata().getName().equals(newPod.getMetadata().getName())) {
                    podInfoService.updatePodInfo(K8sElementInfoUtil.V1PodToPodInfo(newPod));
                } else {
                    onDelete(oldPod, false);
                    onAdd(newPod);
                }
            }

            @Override
            public void onDelete(V1Pod pod, boolean deletedFinalStateUnknown) {
                //log.info("{} pod deleted!\n", pod.getMetadata().getName());
                podInfoService.deletePodInfo(K8sElementInfoUtil.V1PodToPodInfo(pod));
            }
        });
    }

    private void addV1NodeInformerEventHandler() {
        V1NodeInformer.addEventHandler(new ResourceEventHandler<V1Node>() {
            @Override
            public void onAdd(V1Node v1Node) {
                String nodeName = v1Node.getMetadata().getName();
                //log.info("{} node added!\n", nodeName);
                if (nodeInfoService.getNodeInfoByNodeName(nodeName) != null) {
                    nodeInfoService.updateNodeInfo(K8sElementInfoUtil.V1NodeToNodeInfo(v1Node));
                } else {
                    nodeInfoService.insertNodeInfo(K8sElementInfoUtil.V1NodeToNodeInfo(v1Node));
                }
            }

            @Override
            public void onUpdate(V1Node oldNode, V1Node newNode) {
                //log.info("{} => {} node updated!\n", oldNode.getMetadata().getName(), newNode.getMetadata().getName());
                if (oldNode.getMetadata().getName().equals(newNode.getMetadata().getName())) {
                    nodeInfoService.updateNodeInfo(K8sElementInfoUtil.V1NodeToNodeInfo(newNode));
                } else {
                    onDelete(oldNode, false);
                    onAdd(newNode);
                }
            }

            @Override
            public void onDelete(V1Node node, boolean deletedFinalStateUnknown) {
                //log.info("{} node deleted!\n", node.getMetadata().getName());
                nodeInfoService.deleteNodeInfo(K8sElementInfoUtil.V1NodeToNodeInfo(node));
            }
        });
    }


    private void addV1DeploymentInformerEventHandler() {
        V1DeploymentInformer.addEventHandler(new ResourceEventHandler<V1Deployment>() {
            @Override
            public void onAdd(V1Deployment deployment) {
                startTime = System.currentTimeMillis();
                String DeploymentName = deployment.getMetadata().getName();
                String namespace = deployment.getMetadata().getNamespace();
                log.info("{} deployment added!\n", DeploymentName);
                if (deploymentInfoService.getDeploymentInfoByDeploymentNameAndNamespace(DeploymentName, namespace) != null) {
                    deploymentInfoService.updateDeploymentInfo(K8sElementInfoUtil.V1DeploymentToDeploymentInfo(deployment));
                } else {
                    deploymentInfoService.insertDeploymentInfo(K8sElementInfoUtil.V1DeploymentToDeploymentInfo(deployment));
                }
            }

            @Override
            public void onUpdate(V1Deployment oldDeployment, V1Deployment newDeployment) {
                log.info("{} => {} deployment updated!\n", oldDeployment.getMetadata().getName(), newDeployment.getMetadata().getName());
                if (oldDeployment.getMetadata().getName().equals(newDeployment.getMetadata().getName())) {
                    V1DeploymentStatus status = newDeployment.getStatus();
                    if (null != status.getReadyReplicas() && status.getReadyReplicas().equals(status.getReplicas())){
                        endTime = System.currentTimeMillis();
                        log.info("==========deployment {} is total ready, costs {} ms=============", newDeployment.getMetadata().getName(), endTime - startTime);
                        endTime = 0L;
                        startTime = 0L;
                    }
                    deploymentInfoService.updateDeploymentInfo(K8sElementInfoUtil.V1DeploymentToDeploymentInfo(newDeployment));
                } else {
                    onDelete(oldDeployment, false);
                    onAdd(newDeployment);
                }
            }

            @Override
            public void onDelete(V1Deployment deployment, boolean deletedFinalStateUnknown) {
                log.info("{} deployment deleted!\n", deployment.getMetadata().getName());
                deploymentInfoService.deleteDeploymentInfo(K8sElementInfoUtil.V1DeploymentToDeploymentInfo(deployment));
            }
        });
    }


}
